package turkey;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

@RestController
public class PlayerController {
    private int[] opponentGrave = new int[2];
    private int[] selfGrave = new int[2];
    private int[] targetGrave = new int[2];
    private boolean player1ArrivedOpponentGrave = false;
    private String teamName;
    private boolean firstStep = false;

    @RequestMapping(value = "player/start", method = RequestMethod.POST)
    public void start(@RequestBody String playerMapString) {
        ObjectMapper mapper = new ObjectMapper();
        PlayerMap playerMap = null;
        try {
            playerMap = mapper.readValue(playerMapString, PlayerMap.class);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
        player1ArrivedOpponentGrave = false;
        firstStep = true;
        List<List<PosInfo>> remoteMap = playerMap.getMap();
        teamName = playerMap.getName();

        selfGrave = new int[]{playerMap.getSelfGraveRowLen(), playerMap.getSelfGraveColLen()};
        String name = playerMap.getName();
        switch (name) {
            case "cao":
                opponentGrave[0] = 0;
                opponentGrave[1] = 0;
                break;
            case "shu":
                opponentGrave[0] = playerMap.getRowLen() - 1;
                opponentGrave[1] = playerMap.getColLen() - 1;
                break;
        }

        outer:
        for (int i = 0; i < remoteMap.size(); i++) {
            for (int j = 0; j < remoteMap.get(i).size(); j++) {
                PosInfo posInfo = remoteMap.get(i).get(j);
                //更新宝藏
                if (posInfo.isTarget()) {
//                    int down_i = i - 1 <= 0 ? 0 : i - 1;
                    int left_j = j - 1 <= 0 ? 0 : j - 1;
                    targetGrave[0] = i;
                    targetGrave[1] = left_j;
                    break outer;
                }
            }
        }
        System.out.println("Game Start");
    }

    @RequestMapping(value = "player/stop", method = RequestMethod.GET)
    public void stop() {
        System.out.println("Game Over");
    }

    @RequestMapping(value = "player/move", method = RequestMethod.POST)
    public ClientRes move(@RequestBody String playerMapString) {
//        System.out.println(playerMapString);
        ClientRes playersDirection = new ClientRes();
        if (firstStep) {
            if ("shu".equals(teamName)) {
                playersDirection.setPlayer1(Direct.DOWN);
                playersDirection.setPlayer2(Direct.DOWN);
                playersDirection.setPlayer3(Direct.RIGHT);
                playersDirection.setPlayer4(Direct.RIGHT);
            }
            if ("cao".equals(teamName)) {
                playersDirection.setPlayer1(Direct.UP);
                playersDirection.setPlayer2(Direct.UP);
                playersDirection.setPlayer3(Direct.LEFT);
                playersDirection.setPlayer4(Direct.LEFT);
            }
            firstStep = false;
            return playersDirection;
        }
        //1.将服务端传过来的json字符串反序列化为PlayerMap对象
        ObjectMapper mapper = new ObjectMapper();
        PlayerMap playerMap = null;
        try {
            playerMap = mapper.readValue(playerMapString, PlayerMap.class);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
        List<List<PosInfo>> remoteMap = playerMap.getMap();

        //2.获取有用信息：包括当前各个选手位置、下步可以走的位置、宝藏位置
        int[] player1Location = new int[2];
        int[] player2Location = new int[2];
        int[] player3Location = new int[2];
        int[] player4Location = new int[2];
        int[] target = new int[2];

        int colLen = playerMap.getColLen();
        int rowLen = playerMap.getRowLen();
        // 权重为0可以走
        int[][] localMap = new int[rowLen][colLen];
        int[][] localMapWithTarget = new int[rowLen][colLen];
        String targetWith = playerMap.getTargetWith();
        teamName = playerMap.getName();

        // 遍历地图信息
        for (int i = 0; i < remoteMap.size(); i++) {
            for (int j = 0; j < remoteMap.get(i).size(); j++) {
                PosInfo posInfo = remoteMap.get(i).get(j);
                //更新地图
                if (posInfo.isBlock()) {
                    localMap[i][j] = 999; //障碍位置权重
                    localMapWithTarget[i][j] = 999; //障碍位置权重
                }
                //更新宝藏
                if (posInfo.isTarget()) {
                    target[0] = i;
                    target[1] = j;
                }
                //更新选手位置
                if ("shu".equals(teamName)) {
                    if (posInfo.isCao1() || posInfo.isCao2() || posInfo.isCao3() || posInfo.isCao4()) {
                        if (playerMap.getTargetWith() != null && playerMap.getTargetWith().startsWith("S")) {
                            int up_i = i + 1 >= rowLen ? i : i + 1;
                            int down_i = i - 1 <= 0 ? 0 : i - 1;
                            int left_j = j - 1 <= 0 ? 0 : j - 1;
                            int right_j = j + 1 >= colLen ? j : j + 1;
                            // 我方得到target时，敌方以及其上下左右位置权重为999
                            localMapWithTarget[i][j] = 999;
                            localMapWithTarget[down_i][j] = 999;
                            localMapWithTarget[up_i][j] = 999;
                            localMapWithTarget[i][left_j] = 999;
                            localMapWithTarget[i][right_j] = 999;
                        }
                    }
                    if (posInfo.isShu1()) {
                        player1Location[0] = i;
                        player1Location[1] = j;
                    }
                    if (posInfo.isShu2()) {
                        player2Location[0] = i;
                        player2Location[1] = j;
                    }
                    if (posInfo.isShu3()) {
                        player3Location[0] = i;
                        player3Location[1] = j;
                    }
                    if (posInfo.isShu4()) {
                        player4Location[0] = i;
                        player4Location[1] = j;

                    }
                }
                if ("cao".equals(teamName)) {
                    if (posInfo.isShu1() || posInfo.isShu2() || posInfo.isShu3() || posInfo.isShu4()) {
                        if (playerMap.getTargetWith() != null && playerMap.getTargetWith().startsWith("C")) {
                            int up_i = i + 1 >= rowLen ? i : i + 1;
                            int down_i = i - 1 <= 0 ? 0 : i - 1;
                            int left_j = j - 1 <= 0 ? 0 : j - 1;
                            int right_j = j + 1 >= colLen ? j : j + 1;
                            // 我方得到target时，敌方以及其上下左右位置权重为999
                            localMapWithTarget[i][j] = 999;
                            localMapWithTarget[down_i][j] = 999;
                            localMapWithTarget[up_i][j] = 999;
                            localMapWithTarget[i][left_j] = 999;
                            localMapWithTarget[i][right_j] = 999;
                        }
                    }
                    if (posInfo.isCao1()) {
                        player1Location[0] = i;
                        player1Location[1] = j;
                    }
                    if (posInfo.isCao2()) {
                        player2Location[0] = i;
                        player2Location[1] = j;
                    }
                    if (posInfo.isCao3()) {
                        player3Location[0] = i;
                        player3Location[1] = j;
                    }
                    if (posInfo.isCao4()) {
                        player4Location[0] = i;
                        player4Location[1] = j;
                    }
                }
            }
        }

//        System.out.println(Arrays.toString(localMap));
//        for (int i = 0; i < localMap.length; i++) {
//            for (int j = 0; j < localMap[0].length; j++) {
//                System.out.print(localMap[i][j]+" ");
//
//            }
//            System.out.println();
//        }
//        System.out.println("-----");
        //3.计算4个角色各自要走的方向

        if ("shu".equals(teamName)) {
            // player1 先去对方复活点，然后再追targe
            // player1：自己抢到宝藏，回自己家。
            // 敌方抢到宝藏已到他们老家||已到过对方老家，去宝藏重生点。
            // 没任何一方抢到宝藏（对方没抢到宝藏）&&没到过对方老家，去对方家。
            // 剩下所有情况，都去宝藏。包括但不局限于：敌方抢到宝藏且没到敌方老家||自己到达对方老家||除自己的己方人员抢到宝藏
            if ("SHU1".equals(targetWith)) {
                // 得到target时，回复活点
                calculatePlayersDirection(player1Location, 1, selfGrave, localMapWithTarget, playersDirection);
            } else if (playerMap.getOpponentTargetNum() >= 2) {
                calculatePlayersDirection(player1Location, 1, target, localMap, playersDirection);
            } else if ( (playerMap.getTargetWith() != null && playerMap.getTargetWith().startsWith("C")) || (player1ArrivedOpponentGrave)) {
                //追宝藏
                calculatePlayersDirection(player1Location, 1, target, localMap, playersDirection);
            } else if ( (playerMap.getTargetWith() == null || playerMap.getTargetWith().startsWith("S")) && !player1ArrivedOpponentGrave ) {
                //去对方老家
                calculatePlayersDirection(player1Location, 1, opponentGrave, localMap, playersDirection);
                if (player1Location[0] == opponentGrave[0] && player1Location[1] == opponentGrave[1]) {
                    player1ArrivedOpponentGrave = true;
                }
            } else {
                calculatePlayersDirection(player1Location, 1, target, localMap, playersDirection);
            }

            // player2
            //回自己家：自己抢到宝藏||palyer3抢到宝藏
            //去宝藏重生点：player1或player4抢到宝藏||敌方抢到宝藏已到他们老家
            //抢宝藏：剩下的情况
            if ("SHU2".equals(targetWith)) {
                calculatePlayersDirection(player2Location, 2, selfGrave, localMapWithTarget, playersDirection);
            } else if (playerMap.getOpponentTargetNum() >= 2) {
                calculatePlayersDirection(player2Location, 2, target, localMap, playersDirection);
            } else if ((selfGrave[0] == target[0] && selfGrave[1] == target[1]) || ((playerMap.getTargetWith() != null && playerMap.getTargetWith().startsWith("C")) && (target[0] == opponentGrave[0] && target[1] == opponentGrave[1])) ) {
                calculatePlayersDirection(player2Location, 2, targetGrave, localMap, playersDirection);
            } else {
                calculatePlayersDirection(player2Location, 2, target, localMap, playersDirection);
            }

            // player3
            //回自己家：自己抢到宝藏||palyer2抢到宝藏
            //去宝藏重生点：player1或player4抢到宝藏||敌方抢到宝藏已到他们老家
            //抢宝藏：剩下的情况
            if ("SHU3".equals(targetWith)) {
                calculatePlayersDirection(player3Location, 3, selfGrave, localMapWithTarget, playersDirection);
            } else if (playerMap.getOpponentTargetNum() >= 2) {
                calculatePlayersDirection(player3Location, 3, target, localMap, playersDirection);
            } else if ((selfGrave[0] == target[0] && selfGrave[1] == target[1]) || ((playerMap.getTargetWith() != null && playerMap.getTargetWith().startsWith("C")) && (target[0] == opponentGrave[0] && target[1] == opponentGrave[1])) ) {
                calculatePlayersDirection(player3Location, 3, targetGrave, localMap, playersDirection);
            } else {
                calculatePlayersDirection(player3Location, 3, target, localMap, playersDirection);
            }

            // player4
            //只跟着target走
            if ("SHU4".equals(targetWith)) {
                // 得到target时，回复活点
                calculatePlayersDirection(player4Location, 4, selfGrave, localMapWithTarget, playersDirection);
            } else if (playerMap.getOpponentTargetNum() >= 2) {
                calculatePlayersDirection(player4Location, 4, target, localMap, playersDirection);
            } else if( (playerMap.getTargetWith() != null && playerMap.getTargetWith().startsWith("S")) ) {
                calculatePlayersDirection(player4Location, 4, targetGrave, localMap, playersDirection);
            } else {
                // 追target
                calculatePlayersDirection(player4Location, 4, target, localMap, playersDirection);
            }
        }

        if ("cao".equals(teamName)) {
            // player1 先去对方复活点，然后再追targe
            // player1：自己抢到宝藏，回自己家。
            // 敌方抢到宝藏已到他们老家||已到过对方老家，去宝藏重生点。
            // 没任何一方抢到宝藏（对方没抢到宝藏）&&没到过对方老家，去对方家。
            // 剩下所有情况，都去宝藏。包括但不局限于：敌方抢到宝藏且没到敌方老家||自己到达对方老家||除自己的己方人员抢到宝藏
            if ("CAO1".equals(targetWith)) {
                // 得到target时，回复活点
                calculatePlayersDirection(player1Location, 1, selfGrave, localMapWithTarget, playersDirection);
            } else if (playerMap.getOpponentTargetNum() >= 2) {
                calculatePlayersDirection(player1Location, 1, target, localMap, playersDirection);
            } else if ( (playerMap.getTargetWith() != null && playerMap.getTargetWith().startsWith("S")) || (player1ArrivedOpponentGrave)) {
                //追宝藏
                calculatePlayersDirection(player1Location, 1, target, localMap, playersDirection);
            } else if ( (playerMap.getTargetWith() == null || playerMap.getTargetWith().startsWith("C")) && !player1ArrivedOpponentGrave ) {
                //去对方老家
                calculatePlayersDirection(player1Location, 1, opponentGrave, localMap, playersDirection);
                if (player1Location[0] == opponentGrave[0] && player1Location[1] == opponentGrave[1]) {
                    player1ArrivedOpponentGrave = true;
                }
            } else {
                calculatePlayersDirection(player1Location, 1, target, localMap, playersDirection);
            }

            // player2
            //回自己家：自己抢到宝藏||palyer3抢到宝藏
            //去宝藏重生点：player1或player4抢到宝藏||敌方抢到宝藏已到他们老家
            //抢宝藏：剩下的情况
            if ("CAO2".equals(targetWith)) {
                calculatePlayersDirection(player2Location, 2, selfGrave, localMapWithTarget, playersDirection);
            } else if (playerMap.getOpponentTargetNum() >= 2) {
                calculatePlayersDirection(player2Location, 2, target, localMap, playersDirection);
            } else if ((selfGrave[0] == target[0] && selfGrave[1] == target[1]) || ((playerMap.getTargetWith() != null && playerMap.getTargetWith().startsWith("S")) && (target[0] == opponentGrave[0] && target[1] == opponentGrave[1])) ) {
                calculatePlayersDirection(player2Location, 2, targetGrave, localMap, playersDirection);
            } else {
                calculatePlayersDirection(player2Location, 2, target, localMap, playersDirection);
            }

            // player3
            //回自己家：自己抢到宝藏||palyer2抢到宝藏
            //去宝藏重生点：player1或player4抢到宝藏||敌方抢到宝藏已到他们老家
            //抢宝藏：剩下的情况
            if ("CAO3".equals(targetWith)) {
                calculatePlayersDirection(player3Location, 3, selfGrave, localMapWithTarget, playersDirection);
            } else if (playerMap.getOpponentTargetNum() >= 2) {
                calculatePlayersDirection(player3Location, 3, target, localMap, playersDirection);
            } else if ((selfGrave[0] == target[0] && selfGrave[1] == target[1]) || ((playerMap.getTargetWith() != null && playerMap.getTargetWith().startsWith("S")) && (target[0] == opponentGrave[0] && target[1] == opponentGrave[1])) ) {
                calculatePlayersDirection(player3Location, 3, targetGrave, localMap, playersDirection);
            } else {
                calculatePlayersDirection(player3Location, 3, target, localMap, playersDirection);
            }

            // player4
            //只跟着target走
            if ("CAO4".equals(targetWith)) {
                // 得到target时，回复活点
                calculatePlayersDirection(player4Location, 4, selfGrave, localMapWithTarget, playersDirection);
            } else if (playerMap.getOpponentTargetNum() >= 2) {
                calculatePlayersDirection(player4Location, 4, target, localMap, playersDirection);
            } else if( (playerMap.getTargetWith() != null && playerMap.getTargetWith().startsWith("C")) ) {
                calculatePlayersDirection(player4Location, 4, targetGrave, localMap, playersDirection);
            } else {
                // 追target
                calculatePlayersDirection(player4Location, 4, target, localMap, playersDirection);
            }
        }
        return playersDirection;
    }

    // 计算下一步往哪走
    private void calculatePlayersDirection(int[] playerLocation, int playerNum, int[] target, int[][] localMap, ClientRes clientRes) {
        int mapColNmu = localMap[0].length;
        int playerOneDim = playerLocation[0] * mapColNmu + playerLocation[1];
        int targetOneDim = target[0] * mapColNmu + target[1];
        int palyerNext = Dijkstra.calculateNextLocation(localMap, playerOneDim, targetOneDim);

        int distance = playerOneDim - palyerNext;
        Direct direct = Direct.STAY;
        if (distance == mapColNmu) {
            direct = Direct.UP;
        } else if (distance == -mapColNmu) {
            direct = Direct.DOWN;
        } else if (distance == 1) {
            direct = Direct.LEFT;
        } else if (distance == -1) {
            direct = Direct.RIGHT;
        }

        switch (playerNum) {
            case 1:
                clientRes.setPlayer1(direct);
                break;
            case 2:
                clientRes.setPlayer2(direct);
                break;
            case 3:
                clientRes.setPlayer3(direct);
                break;
            case 4:
                clientRes.setPlayer4(direct);
                break;
        }
    }
}
